/* Copyright (c) Microsoft Corporation.
   Licensed under the MIT License. */

/***************************************************************************
	Author: ShonK
	Project: Kauai
	Reviewed:
	Copyright (c) Microsoft Corporation

	Graphic object class.

***************************************************************************/
#include "frame.h"
ASSERTNAME


PGOB GOB::_pgobScreen;

#define kswKindGob 0x526F

/***************************************************************************
	Create the screen gob.  If fgobEnsureHwnd is set, ensures that the
	screen gob has an OS window associated with it.
***************************************************************************/
bool GOB::FInitScreen(ulong grfgob, long ginDef)
{
	PGOB pgob;

	switch (ginDef)
		{
	case kginDraw:
	case kginMark:
	case kginSysInval:
		_ginDefGob = ginDef;
		break;
		}

	if ((pgob = NewObj GOB(khidScreen)) == pvNil)
		return fFalse;
	Assert(pgob == _pgobScreen, 0);

	if (grfgob & fgobEnsureHwnd)
		{
		//REVIEW shonk: create the hwnd and attach it
		RawRtn();
		}

	return fTrue;
}


/***************************************************************************
	Make the GOB a wrapper for the given system window.
***************************************************************************/
bool GOB::FAttachHwnd(HWND hwnd)
{
	if (_hwnd != hNil)
		{
		ReleasePpo(&_pgpt);
		//don't destroy the hwnd
		_hwnd = hNil;
		_hwnd->refCon = 0;
		}
	if (hwnd != hNil)
		{
		if ((_pgpt = GPT::PgptNew(&hwnd->port)) == pvNil)
			return fFalse;
		_hwnd = hwnd;
		if (_hwnd->windowKind != dialogKind)
			_hwnd->windowKind = kswKindGob;
		_hwnd->refCon = (long)this;
		SetRcFromHwnd();
		}
	return fTrue;
}


/***************************************************************************
	Find the GOB associated with the given hwnd (if there is one).
***************************************************************************/
PGOB GOB::PgobFromHwnd(HWND hwnd)
{
	Assert(hwnd != hNil, "nil hwnd");
	PGOB pgob;

	if (hwnd->windowKind != kswKindGob && hwnd->windowKind != dialogKind)
		return pvNil;
	pgob = (PGOB)hwnd->refCon;
	AssertNilOrPo(pgob, 0);
	return pgob;
}


/***************************************************************************
	Static method to get the next
***************************************************************************/
HWND GOB::HwndMdiActive(void)
{
	HWND hwnd;

	if (hNil == (hwnd = (HWND)FrontWindow()))
		return hNil;
	if (hwnd->windowKind < userKind)
		return hNil;
	if (pvNil != _pgobScreen && _pgobScreen->_hwnd == hwnd)
		return hNil;
	return hwnd;
}


/***************************************************************************
	Creates a new MDI window and returns it.  This is normally then
	attached to a gob.
***************************************************************************/
HWND GOB::_HwndNewMdi(PSTZ pstzTitle)
{
	HWND hwnd;
	RCS rcs;
	static long _cact = 0;

	rcs = qd.screenBits.bounds;
	rcs.top += GetMBarHeight() + 25; //menu bar and title
	rcs.left += 5;
	rcs.right -= 105;
	rcs.bottom -= 105;
	OffsetRect(&rcs, _cact * 20, _cact * 20);
	_cact = (_cact + 1) % 5;

	hwnd = (HWND)NewCWindow(pvNil, &rcs, (byte *)pstzTitle, fTrue,
		documentProc, GrafPtr(-1), fTrue, 0);
	if (hNil != hwnd && pvNil != vpmubCur)
		vpmubCur->FAddListCid(cidChooseWnd, (long)hwnd, pstzTitle);
	return hwnd;
}


/***************************************************************************
	Destroy an hwnd.
***************************************************************************/
void GOB::_DestroyHwnd(HWND hwnd)
{
	if (pvNil != vpmubCur)
		vpmubCur->FRemoveListCid(cidChooseWnd, (long)hwnd);
	DisposeWindow((PPRT)hwnd);
}


/***************************************************************************
	The grow area has been hit, track it and resize the window.
***************************************************************************/
void GOB::TrackGrow(PEVT pevt)
{
	Assert(_hwnd != hNil, "gob has no hwnd");
	Assert(pevt->what == mouseDown, "wrong EVT");

	long lw;
	RC rc;
	RCS rcs;

	GetMinMax(&rc);
	rcs = RCS(rc);
	if ((lw = GrowWindow(&_hwnd->port, pevt->where, &rcs)) != 0)
		{
		SizeWindow(&_hwnd->port, SwLow(lw), SwHigh(lw), fFalse);
		_SetRcCur();
		}
}


/***************************************************************************
	Gets the current mouse location in this gob's coordinates (if ppt is
	not nil) and determines if the mouse button is down (if pfDown is
	not nil).
***************************************************************************/
void GOB::GetPtMouse(PT *ppt, bool *pfDown)
{
	if (ppt != pvNil)
		{
		PTS pts;
		long xp, yp;
		PGOB pgob;
		PPRT pprtSav, pprt;

		xp = yp = 0;
		for (pgob = this; pgob != pvNil && pgob->_hwnd == hNil;
				pgob = pgob->_pgobPar)
			{
			xp += pgob->_rcCur.xpLeft;
			yp += pgob->_rcCur.ypTop;
			}

		if (pvNil != pgob)
			pprt = &pgob->_hwnd->port;
		else
			GetWMgrPort(&pprt);
		GetPort(&pprtSav);
		SetPort(pprt);
		GetMouse(&pts);
		SetPort(pprtSav);

		*ppt = pts;
		ppt->xp -= xp;
		ppt->yp -= yp;
		}
	if (pfDown != pvNil)
		*pfDown = FPure(Button());
}


/***************************************************************************
	Makes sure the GOB is clean (no update is pending).
***************************************************************************/
void GOB::Clean(void)
{
	AssertThis(0);
	HWND hwnd;
	RC rc, rcT;
	RCS rcs;
	PPRT pprt;

	if (hNil == (hwnd = _HwndGetRc(&rc)))
		return;

	vpappb->InvalMarked(hwnd);
	rcs = (*hwnd->updateRgn)->rgnBBox;
	GetPort(&pprt);
	SetPort(&hwnd->port);
	GlobalToLocal((PTS *)&rcs);
	GlobalToLocal((PTS *)&rcs + 1);
	rcT = rcs;
	if (!rc.FIntersect(&rcT))
		{
		SetPort(pprt);
		return;
		}

	BeginUpdate(&hwnd->port);
	vpappb->UpdateHwnd(hwnd, &rc);
	EndUpdate(&hwnd->port);
	SetPort(pprt);
}


/***************************************************************************
	Set the window name.
***************************************************************************/
void GOB::SetHwndName(PSTZ pstz)
{
	if (hNil == _hwnd)
		{
		Bug("GOB doesn't have an hwnd");
		return;
		}
	if (pvNil != vpmubCur)
		{
		vpmubCur->FChangeListCid(cidChooseWnd, (long)_hwnd, pvNil,
			(long)_hwnd, pstz);
		}
	SetWTitle(&_hwnd->port, (byte *)pstz);
}


/***************************************************************************
	Static method.  If this hwnd is one of our MDI windows, make it the
	active MDI window.
***************************************************************************/
void GOB::MakeHwndActive(HWND hwnd)
{
	Assert(hwnd != hNil, "nil hwnd");
	GTE gte;
	ulong grfgte;
	PGOB pgob;

	gte.Init(_pgobScreen, fgteNil);
	while (gte.FNextGob(&pgob, &grfgte, fgteNil))
		{
		if (pgob->_hwnd == hwnd)
			{
			SelectWindow(&hwnd->port);
			return;
			}
		}
}


